package ru.reaperoq.taskmanager.filters

import jakarta.servlet.FilterChain
import jakarta.servlet.http.HttpServletRequest
import jakarta.servlet.http.HttpServletResponse
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken
import org.springframework.security.core.context.SecurityContextHolder
import org.springframework.security.core.userdetails.UserDetails
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource
import org.springframework.stereotype.Component
import org.springframework.web.filter.OncePerRequestFilter
import ru.reaperoq.taskmanager.services.JwtService
import ru.reaperoq.taskmanager.services.MyUserDetailsService

@Component
class JwtAuthenticationFilter(
    private val userDetailsService: MyUserDetailsService,
    private val jwtService: JwtService
) : OncePerRequestFilter() {
    override fun doFilterInternal(
        request: HttpServletRequest,
        response: HttpServletResponse,
        filterChain: FilterChain
    ) {
        val authorizationHeader = request.getHeader("Authorization")
        if (authorizationHeader.doesNotContainBearerToken()) {
            filterChain.doFilter(request, response)
            return
        }

        val tokenValue = authorizationHeader.extractTokenValue()
        val username = jwtService.extractUsername(tokenValue)
        println("USERNAME: $username")
        if (username != null && SecurityContextHolder.getContext().authentication == null) {
            val user = userDetailsService.loadUserByUsername(username)

            if (jwtService.isValid(tokenValue, user)) {
                updateContext(user, request)
            }
            filterChain.doFilter(request, response)
        }
    }

    private fun String?.doesNotContainBearerToken() =
        this == null || !this.startsWith("Bearer ")

    private fun String.extractTokenValue() =
        this.substringAfter("Bearer ")

    private fun updateContext(foundUser: UserDetails, request: HttpServletRequest) {
        val token = UsernamePasswordAuthenticationToken(foundUser, null, foundUser.authorities)
        token.details = WebAuthenticationDetailsSource().buildDetails(request)
        SecurityContextHolder.getContext().authentication = token
    }
}